

package w83a.xml;

import org.apache.xpath.XPathAPI;
import org.w3c.dom.*;

import w83a.xml.exception.W83AXmlErrorCodes;
import w83a.xml.exception.W83AXmlException;

import java.util.StringTokenizer;



import javax.xml.transform.TransformerException;

/** Representa un elemento de un documento xml. */

public final class W83AXmlElement implements java.io.Serializable{

	private static final long serialVersionUID = 1L;
   private Element domElem;

   /**
    * Construye un objeto de la clase.
    * 
    * @param domElem
    *           Elemento Dom subyacente.
    */

   W83AXmlElement(Element domElem) {
      this.domElem = domElem;
   }

   /**
    * Devuelve el nombre del elemento.
    * 
    * @return El nombre del elemento.
    */

   public String getName() {
      return this.domElem.getTagName();
   }

   /**
    * Devuelve el valor del elemento.
    * 
    * @return El valor del elemento; null si no existe.
    */

   public String getValue() {

      String val = null;
      Node node;

      node = domElem.getFirstChild();
      if (node != null)
      {
    	  val = node.getNodeValue();
      }

      return val;

   }

   /**
    * Devuelve el atributo del elemento con el nombre especificado.
    * 
    * @param atrib
    *       El nombre del atributo.
    * @return El valor del atributo.
    */

   public String getAttribute(String atrib) {
      return this.domElem.getAttribute(atrib);
   }
   
   /**
    * Establece el valor del elemento.
    * 
    * @param val
    *           El nuevo valor del elemento.
    */

   public void setValue(String val) {

      Node node;
      Document doc;

      node = domElem.getFirstChild();
      if (node != null)
      {
    	  node.setNodeValue(val);
      }
      else {
         doc = domElem.getOwnerDocument();
         node = doc.createTextNode(val);
         domElem.appendChild(node);
      }

   }

   /**
    * Devuelve el padre de este nodo.
    * 
    * @return El elemento buscado; null si no existe.
    */

   public W83AXmlElement getParentElement() {

      W83AXmlElement elem = null;
      Node node;

      node = domElem.getParentNode();

      if (node != null && node instanceof Element) {
         elem = new W83AXmlElement((Element) node);
      }

      return elem;

   }
   
   /**
    * Devuelve el (primer) elemento hijo con el nombre especificado.
    * 
    * @param name
    *           Nombre del elemento buscado.
    * @return El elemento buscado; null si no existe.
    */

   public W83AXmlElement getChildElement(String name) {

      W83AXmlElement elem = null;
      NodeList nodes;
      int count, i;
      Node node;
      String nodeName;

      nodes = domElem.getChildNodes();
      count = nodes.getLength();

      for (i = 0; i < count; i++) {

         node = nodes.item(i);

         if (node.getNodeType() == Node.ELEMENT_NODE) {

            nodeName = node.getNodeName();

            if (nodeName.compareTo(name) == 0) {
               elem = new W83AXmlElement((Element) node);//NOPMD
               break;
            }

         }

      }

      return elem;

   }

   /**
    * Devuelve el (primer) elemento descendiente con el nombre especificado.
    * 
    * @param pathname
    *           Ruta de acceso y nombre del elemento buscado. <br>
    *           La ruta de acceso debe ser relativa al elemento padre.
    * @return El elemento buscado; null si no existe.
    */

   public W83AXmlElement getDescendantElement(String pathname) {

      W83AXmlElement elem = null;
      StringTokenizer strTkr;
      int count, i;
      String name;
      W83AXmlElement parentElem;
      W83AXmlElement childElem;

      strTkr = new StringTokenizer(pathname, "/");
      count = strTkr.countTokens();

      if (count < 1)
      {
    	  elem = getChildElement(pathname);
      }
      else {

         parentElem = this;

         for (i = 0; i < count; i++) {

            name = strTkr.nextToken();
            childElem = parentElem.getChildElement(name);

            if (childElem == null)
            {
            	break;
            }
            else {
               parentElem = childElem;
               if (i == (count - 1))
               {
            	   elem = childElem;
               }
            }

         }

      }

      return elem;

   }

   /**
    * Devuelve la colección de elementos hijo del elemento.
    * 
    * @return La colección mencionada.
    */

   public W83AXmlElements getChildElements() {
      return W83AXmlElement.getChildElements(domElem);
   }

   /**
    * Devuelve el texto xml del elemento.
    * 
    * @param omitXmlHdr
    *           Especifica si omitir la cabecera xml.
    * @return El texto mencionado.
    * @throws W83AXmlException
    *            si se produce algún error.
    */

   public String getStringText(boolean omitXmlHdr) throws W83AXmlException {

      return W83AXmlTransformer.transformXmlElementToXmlStringText(this,
               omitXmlHdr);
   }

   /**
    * Devuelve el texto xml del elemento codificado en UTF-8.
    * 
    * @param omitXmlHdr
    *           Especifica si omitir la cabecera xml.
    * @return El texto mencionado.
    * @throws W83AXmlException
    *            si se produce algún error.
    */

   public byte[] getUtf8Text(boolean omitXmlHdr) throws W83AXmlException {
      
      return W83AXmlTransformer.transformXmlElementToXmlUtf8Text(this,
               omitXmlHdr);
   }

   /**
    * Devuelve el elemento Dom subyacente.
    * 
    * @return El elemento mencionado.
    */

   public Element getDomElement() {
      return this.domElem;
   }

   /**
    * Devuelve la colección de elementos hijo del nodo Dom especificado.
    * 
    * @param domNode
    *           El nodo Dom mencionado.
    * @return La colección mencionada.
    */

   private static W83AXmlElements getChildElements(Node domNode) {

      W83AXmlElements elems = null;
      NodeList domNodes;
      int count, count1, i;
      Node[] domNodes1;
      Node domNode1;
      W83AXmlElement[] elems1;
      W83AXmlElement elem1;

      domNodes = domNode.getChildNodes();
      count = domNodes.getLength();
      domNodes1 = new Node[count];
      count1 = 0;

      for (i = 0; i < count; i++) {

         domNode1 = domNodes.item(i);

         if (domNode1.getNodeType() == Node.ELEMENT_NODE) {
            domNodes1[count1] = domNode1;
            count1++;
         }

      }

      elems1 = new W83AXmlElement[count1];

      for (i = 0; i < count1; i++) {
         domNode1 = domNodes1[i];
         elem1 = new W83AXmlElement((Element) domNode1);//NOPMD
         elems1[i] = elem1;
      }

      elems = new W83AXmlElements(elems1);

      return elems;

   }

   /**
    * Método que obtiene un nodo a través de una expresión
    * XPath.
    * 
    * @param xpathExpression
    *            Expresión que obtiene el valor deseado.
    * @return El valor del nodo elemento. Si no existe se devuelve nulo
    * @throws W83AXmlException
    */

   public W83AXmlElement getXmlElement(String xpathExpression) 
   throws W83AXmlException {

      //String value = null;
      Node node;
      W83AXmlElement element = null;

      try {
         node = XPathAPI.selectSingleNode((Node)getDomElement(),
               xpathExpression);
         if (node != null)
         {
        	 element = new W83AXmlElement((Element)node);
         }
      } 
      catch (TransformerException exc) {
         throw new W83AXmlException(W83AXmlErrorCodes.EC_IRRETRIEVABLE_VALUE, 
               exc);
      }

      return element;

   }
   
   /**
    * Método que obtiene un conjunto de nodos a través de una expresión XPath.
    * 
    * @param xpathExpression
    *           Expresión que obtiene el valor deseado.
    * @return El valor de los nodos elemento. Si no existe se devuelve nulo
    * @throws W83AXmlException
    */
   

   public W83AXmlElements getXmlElements(String xpathExpression)
   throws W83AXmlException {

      NodeList nodeList;
      int counter;
      W83AXmlElements elements = null;
      W83AXmlElement[] elem;
     // W83AXmlElement element;

      try {
         nodeList = XPathAPI.selectNodeList(getDomElement(), xpathExpression);

         elem = new W83AXmlElement[nodeList.getLength()];
         for (counter = 0; counter < nodeList.getLength(); counter++) {
            elem[counter] = new W83AXmlElement((Element)nodeList.item(counter));//NOPMD
         }
         elements = new W83AXmlElements(elem);
         
         return elements;
      }
      catch (TransformerException exc) {
         throw new W83AXmlException(W83AXmlErrorCodes.EC_IRRETRIEVABLE_VALUE,
               exc);
      }
   }
   
} // class XmlElement
